//
// Last.fm session class
//
// Usage:
// 
//   var session = new lastFmSession();
//   
// Methods:
//
//   getStatus()
//   startLogin()
//   startAnonymousLogin()
//   getCurrentTrack()
//   popTrack()
//   getPlaylist()
//   startTune()
//

function lastFmSession()
{
	this._playlistArray = new Array();
	this._status = LASTFM_STATUS_LOGGEDOUT;
}

const LASTFM_STATUS_LOGGEDOUT = 0;
const LASTFM_STATUS_LOGGINGIN = 1;
const LASTFM_STATUS_LOGGEDIN  = 2;

lastFmSession._loginXHR;
lastFmSession._loginEvHdlr;

lastFmSession._anonloginXHR;

lastFmSession._anonHandshakeXHR;
lastFmSession._anonHandshakeHdlr;

lastFmSession._tuneXHR;
lastFmSession._tuneHdlr;
lastFmSession._tuneParams;

lastFmSession._cmdXHR;
lastFmSession._cmdHdlr;

lastFmSession._playlistXHR;
lastFmSession._playlistHdlr;
lastFmSession._playlistArray;
lastFmSession._playlistTitle;

lastFmSession._status;

lastFmSession._session;
lastFmSession._baseUrl;
lastFmSession._basePath;
lastFmSession._user;

lastFmSession.prototype.getStatus = function()
{
	return this._status;
}

lastFmSession.prototype.getTuneParams = function()
{
	return this._tuneParams;
}

lastFmSession.prototype.getPlaylistTitle = function()
{
	return this._playlistTitle;
}

lastFmSession.prototype.onLoginXHRStateChange = function()
{
	if (this._loginXHR.readyState == 4)
	{
		if (this._loginXHR.status == 200)
		{
			this._status = LASTFM_STATUS_LOGGEDIN;
			
			var params = getParamSet(this._loginXHR.responseText);
			
			this._session = params["session"];
			this._baseUrl = params["base_url"];
			this._basePath = params["base_path"] + "/";
			
			if(this._loginEvHdlr)
			{
				this._loginEvHdlr();	
			}
		}
	}
}

lastFmSession.prototype.startLogin = function(username, password, evHdlr)
{
	this._loginEvHdlr = evHdlr;
	
	var request = "http://ws.audioscrobbler.com/radio/handshake.php?";
	request += "version=0.0.9&platform=win32";
	request += "&username=" + username;
	request += "&passwordmd5=" + hex_md5(password);
	request += "&debug=0&partner=";
	
	this._loginXHR = new XMLHttpRequest();
	this._loginXHR.onreadystatechange = createObjectCallback(this, this.onLoginXHRStateChange);
	this._loginXHR.open("GET", request, true);
	this._loginXHR.send("");	

	this._status = LASTFM_STATUS_LOGGINGIN;
}

lastFmSession.prototype.onAnonHandshakeXHRStateChange = function()
{
	if (this._anonHandshakeXHR.readyState == 4)
	{
		if (this._anonHandshakeXHR.status == 200)
		{
			var params = getParamSet(this._anonHandshakeXHR.responseText);
			
			this._session = params["session"];
			this._baseUrl = params["base_url"];
			this._basePath = params["base_path"];

			if(this._anonHandshakeHdlr)
			{
				this._anonHandshakeHdlr();	
			}
			
			this._status = LASTFM_STATUS_LOGGEDIN;
		}
	}
}

lastFmSession.prototype.onAnonLoginXHRStateChange = function()
{
	if (this._anonLoginXHR.readyState == 4)
	{
		if (this._anonLoginXHR.status == 200)
		{
			var parser = new DOMParser();
			var doc = parser.parseFromString(this._anonLoginXHR.responseText, "text/xml");
			var stringNodes = doc.getElementsByTagName("string");
			
			var user = stringNodes[0].firstChild.nodeValue;
			var sessionKey = stringNodes[1].firstChild.nodeValue;
			
			var request = "http://ext.last.fm/1.0/radio/webclient/handshake.php?";
			request += "sessionKey=" + sessionKey;
			request += "&user=" + user;
			
			this._anonHandshakeXHR = new XMLHttpRequest();
			this._anonHandshakeXHR.onreadystatechange = createObjectCallback(this, this.onAnonHandshakeXHRStateChange);
			this._anonHandshakeXHR.open("GET", request, true);
			this._anonHandshakeXHR.send("");
		}
	}
}

lastFmSession.prototype.startAnonymousLogin = function(evHdlr)
{
	this._anonHandshakeHdlr = evHdlr;
	
	var request = "http://ext.last.fm/1.0/webclient/xmlrpc.php";
	var postData = "<methodCall><methodName>getSession</methodName><params /></methodCall>";
	
	this._anonLoginXHR = new XMLHttpRequest();
	this._anonLoginXHR.onreadystatechange = createObjectCallback(this, this.onAnonLoginXHRStateChange);
	this._anonLoginXHR.open("POST", request, true);
	this._anonLoginXHR.send(postData);	

	this._status = LASTFM_STATUS_LOGGINGIN;
}

lastFmSession.prototype.getCurrentTrack = function()
{
	if(this._playlistArray.length == 0)
		return null;
		
	return this._playlistArray[0];
}

lastFmSession.prototype.popTrack = function()
{
	if(this._playlistArray.length != 0)
	{
		this._playlistArray.splice(0, 1);
	}
}

lastFmSession.prototype.onPlaylistXHRStateChange = function()
{
	if (this._playlistXHR.readyState == 4)
	{
		if (this._playlistXHR.status == 200)
		{
			var parser = new DOMParser();
			var doc = parser.parseFromString(this._playlistXHR.responseText, "text/xml");
			
			var playlist = doc.getElementsByTagName("playlist")[0];
			var trackList = playlist.getElementsByTagName("trackList")[0];
			var tracks = trackList.getElementsByTagName("track");
			
			this._playlistTitle = getChildNodeText(playlist, "title");
				
			for(var i = 0; i < tracks.length; i++)
			{
				var track = tracks[i];

				var trackObj = new Object();
				trackObj.location = getChildNodeText(track, "location");
				trackObj.title = getChildNodeText(track, "title");
				trackObj.album = getChildNodeText(track, "album");
				trackObj.creator = getChildNodeText(track, "creator");
				trackObj.image = getChildNodeText(track, "image");

				this._playlistArray.push(trackObj);
			}
					
			if(this._playlistHdlr)
			{
				this._playlistHdlr();
			}
		}
	}
}

lastFmSession.prototype.getPlaylist = function(evHdlr)
{
	this._playlistHdlr = evHdlr;
	
	var request = "http://" + this._baseUrl + this._basePath;
	request += "xspf.php?sk=" + this._session + "&discovery=0&desktop=1.3.1.1";
	
	this._playlistXHR = new XMLHttpRequest();
	this._playlistXHR.overrideMimeType("text/xml");
	this._playlistXHR.onreadystatechange = createObjectCallback(this, this.onPlaylistXHRStateChange);
	this._playlistXHR.open("GET", request, true);
	this._playlistXHR.send("");
}

lastFmSession.prototype.onTuneXHRStateChange = function()
{
	if (this._tuneXHR.readyState == 4)
	{
		if (this._tuneXHR.status == 200)
		{
			if(this._tuneHdlr)
			{			
				this._tuneHdlr();
			}
		}
	}
}
		
lastFmSession.prototype.startTune = function(lastFmUrl, evHdlr)
{
	this._tuneHdlr = evHdlr;

	var request = "http://" + this._baseUrl + this._basePath;
	request += "adjust.php?lang=en&session=" + this._session + "&url=" + lastFmUrl;
	
	this._tuneXHR = new XMLHttpRequest();
	this._tuneXHR.onreadystatechange = createObjectCallback(this, this.onTuneXHRStateChange);
	this._tuneXHR.open("GET", request, true);
	this._tuneXHR.send("");
	
	// reset the playlist
	this._playlistArray = new Array();	
}

lastFmSession.prototype.onCmdXHRStateChange = function()
{
	if (this._cmdXHR.readyState == 4)
	{
		if (this._cmdXHR.status == 200)
		{
			if(this._cmdHdlr)
			{
				this._cmdHdlr();
			}
		}
	}
}

lastFmSession.prototype.sendCommand = function(cmd, evHdlr)
{
	this._cmdHdlr = evHdlr;

	var request = "http://ws.audioscrobbler.com/radio/control.php?"
	request += "session=" + this._session + "&command=" + cmd + "&debug=0";

	this._cmdXHR = new XMLHttpRequest();
	this._cmdXHR.onreadystatechange = createObjectCallback(this, this.onCmdXHRStateChange);
	this._cmdXHR.open("GET", request, true);
	this._cmdXHR.send("");
}

lastFmSession.prototype.love = function(evHdlr)
{
	this.sendCommand("love", evHdlr);
}

lastFmSession.prototype.ban = function(evHdlr)
{
	this.sendCommand("ban", evHdlr);
}

lastFmSession.prototype.skip = function(evHdlr)
{
	this.sendCommand("skip", evHdlr);
}

function getChildNodeText(node, childName)
{
	var childSet = node.getElementsByTagName(childName);
	
	if(childSet.length == 0)
		return null;
		
	if(!childSet[0].hasChildNodes())
		return null;
		
	return childSet[0].firstChild.nodeValue;
}

function getParamSet(text)
{
	var vars = text.split(/[\r\n\|&]/);
	var params = new Array();

	for(var v = 0;v < vars.length; v++)
	{
		var line = vars[v];
		var splitPos = line.indexOf("=");

		if(splitPos != -1)
		{
			var part1 = line.substr(0, splitPos);
			var part2 = line.substr(splitPos + 1);
			
			params[part1] = part2;
		}			
	}
	
	return params;
}

function createObjectCallback(obj, fn)
{
	return function() { fn.apply(obj, arguments); };
}

